#include "driver2socks.h"
#include <array>
#include <cctype>
#include <cstdio>
#include <cstring>
#include <deque>
#include <memory>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include <thread>
#include <unordered_map>

#include <windivert.h>
#include "asio.hpp"
#include "lwipstack.h"
#include "windivert_driver.h"
#include "wintun_driver.h"
#include "iocontext.h"
#include "socks_client.hpp"
#include  "netpacket_pool.h"
extern "C"{
#include "lwip/priv/tcp_priv.h"
}

//#define USE_WINDIVERT

using namespace driver2socks;

const Driver2SocksConfig* g_config;

void driver2socksStart(const Driver2SocksConfig *config) {

    g_config = config;
    if (g_config->use_wintun) {
        std::unique_ptr<WintunDriver> win_tun = std::make_unique<WintunDriver>();
        LWIPStack::getInstance().init();

        //tcp数据注入到驱动入站方向
        LWIPStack::getInstance().set_output_function(
            std::bind(&WintunDriver::doWrite,win_tun.get(),std::placeholders::_1));
        if (config->enable_ipv6) {
            LWIPStack::getInstance().set_outputv6_function(
                std::bind(&WintunDriver::doWrite,win_tun.get(),std::placeholders::_1));
        }


        //从驱动中读取数据
        win_tun->init([](std::shared_ptr<NetPacket> bf) {
            LWIPStack::getInstance().strand_ip_input(bf);
        });
        while (true) {
            Sleep(60000);
        }
    } else {
        auto driver = std::make_shared<WindivertDriver>(config->app_names);
        LWIPStack::getInstance().init();

        //tcp数据注入到驱动入站方向
        LWIPStack::getInstance().set_output_function(
            std::bind(&WindivertDriver::doWrite,driver.get(),std::placeholders::_1));
        if (config->enable_ipv6) {
            LWIPStack::getInstance().set_outputv6_function(
                std::bind(&WindivertDriver::doWrite,driver.get(),std::placeholders::_1));
        }


        //从驱动中读取数据
        driver->run([](std::shared_ptr<NetPacket> bf) {
            LWIPStack::getInstance().strand_ip_input(bf);
        });
        while (true) {
            Sleep(60000);
        }
    }

}
